package com.caoaman.sharding.config;

import com.caoaman.sharding.utils.DataSourceUtil;
import com.caoaman.sharding.utils.shardingarithmetic.PreciseDatabaseShardingAlgorithm;
import com.caoaman.sharding.utils.shardingarithmetic.PreciseTableShardingAlgorithm;
import com.caoaman.sharding.utils.shardingarithmetic.RangeDatabaseShardingAlgorithm;
import com.caoaman.sharding.utils.shardingarithmetic.RangeTableShardingAlgorithm;
import org.apache.shardingsphere.api.config.sharding.KeyGeneratorConfiguration;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;

/**
 * @ClassName: ShardingConfig
 * @Description: sharding配置
 * @Author: CaoAMan
 * @Create: 2021-12-18 15:53
 */
@SpringBootConfiguration
public class ShardingConfig {


    /**
     * 逻辑表名称
     */
    private final String LOGICAL_TABLE = "t_order";

    /**
     * 广播表
     */
    private static final List<String> tableList = new ArrayList<>();
    static {
        tableList.add("t_order_relation");
    }

    /**
     * 分片键
     */
    private final String DATABASE_SHARDING_COLUMN = "save_time_com";


    @Bean
    DataSource getShardingDataSource() throws SQLException {

        // 分片规则配置对象
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        // 规则配置
        shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
        // 数据库分片算法（精确、范围），按年分库
        shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration(DATABASE_SHARDING_COLUMN, new PreciseDatabaseShardingAlgorithm(), new RangeDatabaseShardingAlgorithm()));
        // 表分片算法（精确、范围），按月分表
        shardingRuleConfig.setDefaultTableShardingStrategyConfig(new StandardShardingStrategyConfiguration(DATABASE_SHARDING_COLUMN, new PreciseTableShardingAlgorithm(), new RangeTableShardingAlgorithm()));
        // 默认库，如果存在广播表和绑定表也可在此配置
        shardingRuleConfig.setDefaultDataSourceName("default_dataSource");
        // 全局表配置
        shardingRuleConfig.setBroadcastTables(tableList);
        // 开启日志打印
        final Properties properties = new Properties();
        properties.setProperty("sql.show", "true");
        // 数据源配置
        return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, properties);
    }


    TableRuleConfiguration getOrderTableRuleConfiguration() {

        // 暂定为两年，关于此表达式，可查看官方文档 https://shardingsphere.apache.org/document/legacy/4.x/document/cn/features/sharding/other-features/inline-expression/
        String inLineExpressionStr = "dataSource_2021." + LOGICAL_TABLE + "_20210${1..9}" + "," + "dataSource_2022." + LOGICAL_TABLE + "_20220${1..9}" + "," +
                "dataSource_2021." + LOGICAL_TABLE + "_20211${0..2}" + "," + "dataSource_2022." + LOGICAL_TABLE + "_20221${0..2}";
        final TableRuleConfiguration ruleConfiguration = new TableRuleConfiguration("t_order", inLineExpressionStr);
        // 设置主键生成策略
        ruleConfiguration.setKeyGeneratorConfig(getKeyGeneratorConfiguration());
        return ruleConfiguration;
    }

    private KeyGeneratorConfiguration getKeyGeneratorConfiguration() {

        return new KeyGeneratorConfiguration("SNOWFLAKE", "id");
    }


    private Map<String, DataSource> createDataSourceMap() {
        // key为数据源名称，后面分片算法取得就是这个，value为具体的数据源
        final HashMap<String, DataSource> shardingDataSourceMap = new HashMap<>();
        shardingDataSourceMap.put("default_dataSource", DataSourceUtil.createDataSource("com.mysql.cj.jdbc.Driver",
                "jdbc:mysql://101.37.152.97:3306/sharding?userUnicode=ture&characterEncoding=utf8&serverTimezone=GMT%2B8",
                "root",
                "123456"));
        shardingDataSourceMap.put("dataSource_2021", DataSourceUtil.createDataSource("com.mysql.cj.jdbc.Driver",
                "jdbc:mysql://101.37.152.97:3306/order_2021?userUnicode=ture&characterEncoding=utf8&serverTimezone=GMT%2B8",
                "root",
                "123456"));
        shardingDataSourceMap.put("dataSource_2022", DataSourceUtil.createDataSource("com.mysql.cj.jdbc.Driver",
                "jdbc:mysql://101.37.152.97:3306/order_2022?userUnicode=ture&characterEncoding=utf8&serverTimezone=GMT%2B8",
                "root",
                "123456"));
        return shardingDataSourceMap;
    }

}
